package com.ckr.config;

import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

/**
 * @author Shadowckr
 * @create 2022-01-16 12:13
 */

/*
Spring Security的两个主要目标是 “认证” 和 “授权”（访问控制）。
“认证”（Authentication）
身份验证是关于验证您的凭据，如用户名/用户ID和密码，以验证您的身份。
身份验证通常通过用户名和密码完成，有时与身份验证因素结合使用。
 “授权” （Authorization）
授权发生在系统成功验证您的身份后，最终会授予您访问资源（如信息，文件，数据库，资金，位置，几乎任何内容）的完全权限。
这个概念是通用的，而不是只在Spring Security中存在。
 */

@EnableWebSecurity// 开启WebSecurity模式
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 定制请求的授权规则
        // 首页所有人可以访问
        // http.authorizeRequests().antMatchers(&quot;/**&quot;).hasRole(&quot;USER&quot;).and().formLogin();
        // There was an unexpected error (type=Forbidden, status=403).403:Forbidden
        http.authorizeHttpRequests().antMatchers("/").permitAll()
                .antMatchers("/level1/**").hasRole("vip1")
                .antMatchers("/level2/**").hasRole("vip2")
                .antMatchers("/level3/**").hasRole("vip3");

        // 开启自动配置的登录功能
        // /login请求来到登录页
        // /login?error重定向到这里表示登录失败
        // 点击formLogin()进去看源码注释（十分重要）
        // .loginPage(&quot;/authentication/login&quot;) // default is /login with an HTTP get
        http.formLogin()
                .usernameParameter("username")
                .passwordParameter("password")
                .loginPage("/toLogin")
                .loginProcessingUrl("/login");// 登录表单提交请求
        // 开启自动配置的注销的功能
        // /logout 注销请求
//        http.logout();
        // 注销成功后跳转到指定页面
        http.logout().logoutSuccessUrl("/");
        //关闭csrf功能:跨站请求伪造，默认只能通过post方式提交logout请求
        http.csrf().disable();
        //记住我，定制记住我的参数！
        http.rememberMe().rememberMeParameter("remember");
    }

    //定义认证规则
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //在内存中定义，也可以在jdbc中去拿...
        //我们要将前端传过来的密码进行某种方式加密，否则就无法登录，修改代码。
        //Spring security 5.0中新增了多种加密方式，也改变了密码的格式。
        //要想我们的项目还能够正常登录，需要修改一下configure中的代码。
        //spring security 官方推荐的是使用BCrypt加密方式。
//        auth.inMemoryAuthentication()
//                .withUser("ckr").password("666666").roles("vip1", "vip2")
//                .and()
//                .withUser("root").password("123456").roles("vip1", "vip2", "vip3")
//                .and()
//                .withUser("guest").password("123456").roles("vip1");
        auth.inMemoryAuthentication()
                .passwordEncoder(new BCryptPasswordEncoder())
                .withUser("ckr").password(new BCryptPasswordEncoder().
                encode("666666")).roles("vip1", "vip2")
                .and()
                .withUser("root").password(new BCryptPasswordEncoder().
                encode("123456")).roles("vip1", "vip2", "vip3")
                .and()
                .withUser("guest").password(new BCryptPasswordEncoder().
                encode("123456")).roles("vip1");
    }
}
